/**
 ******************************************************************************
 * @file	bl_sleep.c
 * @brief	LCD背光调节


 * 5秒没有输入调低屏幕亮度，10 秒没有输入则关闭屏幕，
 * 控制台输入
 * ./bl_sleep.elf -t 10 -D /dev/input/event0


- 2016-9-30,MenglongWu,MenglongWoo@aliyun.com
 	- brief

*/


#include <linux/input.h>

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <getopt.h>

#include "autoconfig.h"
/*
 * 不要将MIN_LEVEL调成0，否则及时当背光打开时用户也看不到屏幕内容，
 * 误以为设备损坏，保证最小亮度也是能看到屏幕内容的
*/
#define MIN_LEVEL       (10)				// 可调节最暗亮度
#define AFTER_N_SEC	(5)				// 最后n秒调暗背光
#define LOW_POWER_LEVEL (30)


char *device   = "/dev/input/event1";			// 默认设备
char *bl_dev = "/sys/class/backlight/mxs-bl/";		// LCD背光电源
int timeout   = 30;					// 无操作超时
int level     = 80;					// 关闭前LCD背光亮度


char strout[128];
static void print_usage(const char *prog)
{
	printf("Usage: %s [-DsbdlHOLC3]\n", prog);
	puts("  -D --device   device to use (default /dev/input/event0)\n"
	     "  -p --power    backlight power (default /sys/class/backlight/mxs-bl/)\n"
	     "  -t --timeout  no input event timeout (30 sec)\n");
	exit(1);
}


static void parse_opts(int argc, char *argv[])
{
	while (1) {
		static const struct option lopts[] = {
			{ "device",  1, 0, 'D' },
			{ "timeout", 1, 0, 't' },
			{ "bl_dev", 1, 0, 'p' },
			{ NULL, 0, 0, 0 },
		};
		int c;

		c = getopt_long(argc, argv, "D:p:t:", lopts, NULL);

		if (c == -1) {
			break;
		}

		switch (c) {
		case 'D':
			device = optarg;
			break;
		case 'p':
			bl_dev = optarg;
			break;
		case 't':
			timeout = atoi(optarg);
			if (timeout < 10) {
				timeout = 10;
			} else if (timeout > 5 * 60) {
				timeout = 5 * 60;
			}
			break;
		default:
			print_usage(argv[0]);
			break;
		}
	}
}


static inline void full_bl_level()
{
	snprintf(strout, 128, "echo 80 > " "%s" "/brightness", bl_dev);
	system(strout);
}




#if defined(CONFIG_BL_LOW_POWER_LEVEL)
static inline void save_bl_level()
{
	FILE *fp;
	char strout[128];

	snprintf(strout, 128, "cat " "%s" "/brightness", bl_dev);
	fp = popen((char *)strout, "r");
	if (fp == NULL) {
		return ;
	}

	fscanf(fp, "%d", &level);
	pclose(fp);

	if (level < MIN_LEVEL) {
		level = 100;
	}
}
static inline void restore_bl_level()
{
	snprintf(strout, 128, "echo %d > " "%s" "/brightness", level, bl_dev);
	system(strout);
}

/**
 * @brief	调低背光亮度
 * @remarks	如果但当前背光亮度小于低低功耗背光(LOW_POWER_LEVEL)则不调节
 */

static inline void low_bl_level()
{
	FILE *fp;
	int old_level;

	snprintf(strout, 128, "cat " "%s" "/brightness", bl_dev);
	fp = popen((char *)strout, "r");
	if (fp == NULL) {
		return ;
	}

	fscanf(fp, "%d", &old_level);
	pclose(fp);
	if (old_level < LOW_POWER_LEVEL) {
		return ;
	}


	snprintf(strout, 128, "echo 30 > ""%s""/brightness", bl_dev);
	system(strout);
}



#else
static inline void save_bl_level() {}
static inline void restore_bl_level() {}
static inline void low_bl_level() {}
#endif


static inline void off_bl_power()
{
	snprintf(strout, 128, "echo 1 >" "%s" "/bl_power", bl_dev);
	system(strout);
}

static inline void on_bl_power()
{
	snprintf(strout, 128, "echo 0 > ""%s""/bl_power", bl_dev);
	system(strout);
}


int fd;

// 自动检测 /dev/input 输入，如果30s内没有任何输入关闭LCD背光
// 检测间隔为1s
#define KS_UP 		(0)
#define KS_DOWN 	(1)
#define KS_PRESS 	(2)
void *ThreadBlacklight(void *arg)
{
	struct input_event evt;

	fd = open(device, O_RDWR);
	if (fd < 0) {
		printf("fail open device %s\n", device);
		return 0;
	}


	int len;
	int loop;
	while(1) {
		len = read(fd, &evt, sizeof(evt));
		if (len != -1) {

			if (EV_KEY == evt.type) {
				// printf("tm t %x c %x(%c) v %x(%c)\n",
				//        evt.type,
				//        evt.code, evt.code,
				//        evt.value, evt.value);
				// printf("type:%d,code:%d,value:%d(%c)\n", evt.type,
				// 	evt.code,evt.code,
				// 	evt.value, evt.value);
				printf("[%d %6d] code %d ",
					evt.time.tv_sec,
					evt.time.tv_usec,
					evt.code);

				switch (evt.value) {
				case KS_UP:
					printf("keyup");
					break;
				case KS_DOWN:
					printf("keydown");
					break;
				case KS_PRESS:
					printf("keypress");
					break;
				}
			} else if(EV_SYN == evt.type) {
				printf("syn event");
			}

		}
		printf("\n");

	}
	close(fd);
}

int main(int argc, char *argv[])
{
	parse_opts(argc, argv);
	printf("%2.2x  %2.2x\n", 'u','\n');
	while(1) {
		// printf("%c%c%cu\n",0xff,0xff,0xff);
		printf("\r\n");
		usleep(1000);
	}
	// 启动后将背光点亮，并保存背光亮度等级
	// on_bl_power();
	// full_bl_level();
	// save_bl_level();
	ThreadBlacklight(NULL);

}
 